package com.liuym.admin.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.liuym.admin.properties.OssProperties;
import com.liuym.admin.repository.mapper.ExportLogMapper;
import com.liuym.admin.service.ExportService;
import com.liuym.admin.service.ImportAndExportService;
import com.liuym.admin.service.TableNameService;
import com.liuym.common.constants.Constants;
import com.liuym.common.dubbo.classes.api.ClassesDubboService;
import com.liuym.common.dubbo.classes.dto.ClassDTO;
import com.liuym.common.dubbo.student.api.StudentDubboService;
import com.liuym.common.dubbo.student.api.StudentScoreDubboService;
import com.liuym.common.dubbo.student.dto.StudentDTO;
import com.liuym.common.dubbo.student.dto.StudentScoreDTO;
import com.liuym.common.exception.AdminException;
import com.liuym.common.exception.ClassException;
import com.liuym.common.exception.StudentException;
import com.liuym.common.utils.DateUtil;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author Liuym
 * @date 2018/12/10 14:51
 * @describe：
 */

@Service
public class ImportAndExportServiceImpl implements ImportAndExportService {

    private static Logger logger = LoggerFactory.getLogger(ImportAndExportServiceImpl.class);

    @Reference(version = "${student.dubbo.version}")
    private StudentDubboService studentDubboService;

    @Reference(version = "${student.dubbo.version}")
    private StudentScoreDubboService studentScoreDubboService;

    @Reference(version = "0.0.1")
    private ClassesDubboService classesDubboService;

    @Autowired
    private OssProperties ossProperties;

    @Autowired
    private ExportLogMapper exportLogMapper;

    @Autowired
    private TableNameService tableNameService;

    @Autowired
    private ExportService exportService;

    @Override
    public Map<String, Object> importData(String fileName, String infoType, String operator) throws AdminException {
        if ("xlsx".equals(fileName.substring(fileName.lastIndexOf(".") + 1))) {
            if ("studentInfo".equals(infoType)) {
                return importStudentByExcel2007(fileName, operator);
            }
            if ("classInfo".equals(infoType)) {
                return importClassByExcel2007(fileName);
            }
            if ("studentScoreInfo".equals(infoType)) {
                return importStudentScoreByExcel2007(tableNameService.findByTableAndTime(
                        Constants.STUDENT_SCORE_TABLE_NAME).getTableName(), fileName, operator);
            }
            if ("classScoreInfo".equals(infoType)) {
                return importClassScoretByExcel2007(fileName, operator);
            }
        }
        return null;
    }

    @Override
    public Map<String, Object> exportData(String type, int year, long classNumber, String operator) throws AdminException {
        if ("studentScoreInfo".equals(type)) {
            if (classNumber != 0) {
                String className = null;
                try {
                    className = classesDubboService.getClassByNumber(classNumber).getClassName();
                } catch (ClassException e) {
                    logger.error("error", e);
                    throw AdminException.internalServerError();
                }
                List<StudentDTO> studentDTOList = new ArrayList<>();
                try {
                    studentDTOList = studentDubboService.getStudentByClass(classNumber);
                } catch (StudentException e) {
                    logger.error("error", e);
                    throw AdminException.internalServerError();
                }
                if (studentDTOList != null && studentDTOList.size() > 0) {
                    List<String> title = new ArrayList<>();
                    title.addAll(Arrays.asList("学号,姓名,职位,班级编号,操行分数")); //csv 标题
                    List<List<String>> content = new ArrayList<>(); //csv内容
                    studentDTOList.stream().forEach(studentDTO -> {
                        List<String> record = new ArrayList<>();
                        record.add(studentDTO.getStudentNumber().toString());
                        record.add(studentDTO.getName());
                        record.add(studentDTO.getDuty());
                        record.add(studentDTO.getClassNumber().toString());
                        record.add(studentDTO.getScore().toString());
                        content.add(record);
                    });
                    String uploadPath = "grade/studentInfo/exportData/"; //定义文件名
                    String uploadName = className + "学生操行信息导出数据" + DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + "-" + operator;
                    exportService.export(uploadName, uploadPath, title, content, operator, 2);

                }
            } else {
                //todo 批量导出班级学生信息
                List<ClassDTO> classDTOList = new ArrayList<>();
                try {
                    classDTOList = classesDubboService.getClassByYear(year);
                } catch (ClassException e) {
                    logger.error("上传异常！", e);
                    throw AdminException.internalServerError();
                }
                classDTOList.stream().forEach(classDTO -> {
                    List<StudentDTO> studentDTOList = new ArrayList<>();
                    try {
                        studentDTOList = studentDubboService.getStudentByClass(classDTO.getClassNumber());
                    } catch (StudentException e) {
                        logger.error("error", e);
                    }
                    if (studentDTOList != null && studentDTOList.size() > 0) {
                        List<String> title = new ArrayList<>();
                        title.addAll(Arrays.asList("学号,姓名,职位,班级编号,操行分数")); //csv 标题
                        List<List<String>> content = new ArrayList<>(); //csv内容
                        studentDTOList.stream().forEach(studentDTO -> {
                            List<String> record = new ArrayList<>();
                            record.add(studentDTO.getStudentNumber().toString());
                            record.add(studentDTO.getName());
                            record.add(studentDTO.getDuty());
                            record.add(studentDTO.getClassNumber().toString());
                            record.add(studentDTO.getScore().toString());
                            content.add(record);
                        });
                        String uploadPath = "grade/studentInfo/exportData/"; //定义文件名
                        String uploadName = classDTO.getClassName() + "学生操行信息导出数据" + DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + "-" + operator;
                        try {
                            exportService.export(uploadName, uploadPath, title, content, operator, 2);
                        } catch (AdminException e) {
                            e.printStackTrace();
                        }

                    }
                });

            }
        } else {
            List<ClassDTO> classDTOList = new ArrayList<>();
            try {
                classDTOList = classesDubboService.getClassByYear(year);
            } catch (ClassException e) {
                logger.error("上传异常！", e);
                throw AdminException.internalServerError();
            }
            if (classDTOList != null && classDTOList.size() > 0) {

                List<String> title = new ArrayList<>();
                title.addAll(Arrays.asList("班级编号,班级名称,班长姓名,量化总分")); //csv 标题
                List<List<String>> content = new ArrayList<>(); //csv内容
                classDTOList.stream().forEach(classDTO -> {
                    List<String> record = new ArrayList<>();
                    record.add(classDTO.getClassNumber().toString());
                    record.add(classDTO.getClassName());
                    record.add(classDTO.getMonitor());
                    record.add(classDTO.getScore().toString());
                    content.add(record);
                });
                String uploadPath = "grade/classInfo/exportData/"; //定义文件名
                String uploadName = year + "级班级量化信息导出数据" + DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + "-" + operator;
                exportService.export(uploadName, uploadPath, title, content, operator, 2);
            }
        }
        return null;
    }

    /**
     * 2007版导入班级操行
     *
     * @param fileName
     * @param operator
     * @return
     */
    private Map<String, Object> importClassScoretByExcel2007(String fileName, String operator) {
        return null;
    }

    /**
     * 2007版导入学生操行
     *
     * @param fileName
     * @param operator
     * @return
     */
    private Map<String, Object> importStudentScoreByExcel2007(String tableName, String fileName, String operator) throws AdminException {
        List<StudentScoreDTO> studentScoreDTOList = new ArrayList<StudentScoreDTO>();
        boolean startCount = false;
        int totalCount = 0;
        int importSuccessCount = 0;
        int importFailCount = 0;
        FileInputStream input = null;
        XSSFWorkbook wb = null;
        try {
            input = new FileInputStream(new File(fileName));
            wb = new XSSFWorkbook(new BufferedInputStream(input));
        } catch (IOException e) {
            e.printStackTrace();
        }
        XSSFSheet sheet = wb.getSheetAt(0);
        StudentScoreDTO studentScoreDTO = null;
        for (int rows = 0; rows <= sheet.getLastRowNum(); rows++) {
            XSSFRow row = sheet.getRow(rows);
            String content = null;
            studentScoreDTO = new StudentScoreDTO();
            for (int columns = 0; columns < row.getLastCellNum(); columns++) {
                XSSFCell cell = row.getCell(columns);
                if (cell != null) {
                    if ("".equals(cell.toString())) {
                        content = "";
                    }
                    switch (cell.getCellTypeEnum()) {
                        case STRING:
                            content = cell.getStringCellValue();
                            break;
                        case NUMERIC:
                            if (columns == 0) {
                                DecimalFormat df = new DecimalFormat("0");
                                content = df.format(cell.getNumericCellValue());
                                break;
                            }
                            if (columns == 4) {
                                DecimalFormat df = new DecimalFormat("0");
                                content = df.format(cell.getNumericCellValue());
                                break;
                            }
                            if (columns == 5) {
                                DecimalFormat df = new DecimalFormat("0");
                                content = df.format(cell.getNumericCellValue());
                                break;
                            }
                            break;
                        case FORMULA: // 空值
                            break;
                        default:
                            break;
                    }
                    if (content != null && content != "") {
                        if (columns == 0 && isNumber(content)) {
                            startCount = true;
                            totalCount++;
                        }
                        if (columns == 0 && !isNumber(content) && startCount) {
                            startCount = false;
                        }
                        if (columns == row.getLastCellNum() - 1 && startCount) {
                            studentScoreDTO.setOperateDate(new Date());
                            studentScoreDTO.setOperator(operator);
                            studentScoreDTOList.add(studentScoreDTO);
                        }
                        content = content.trim().replace(" ", "");
                        if (startCount) {
                            switch (columns) {
                                case 0:
                                    studentScoreDTO.setStudentNumber(Long.parseLong(content));
                                    break;
                                case 1:
                                    studentScoreDTO.setName(content);
                                    break;
                                case 2:
                                    studentScoreDTO.setReason(content);
                                    break;
                                case 3:
                                    studentScoreDTO.setRemark(content);
                                    break;
                                case 4:
                                    studentScoreDTO.setApplyScore(Integer.parseInt(content));
                                    break;
                                case 5:
                                    studentScoreDTO.setFinallyScore(Integer.parseInt(content));
                                    break;
                                case 6:
                                    studentScoreDTO.setPage(content);
                                    break;
                                default:
                                    break;
                            }
                        }

                    }

                }
            }

        }
        long begain = System.currentTimeMillis();
        Map<String, Object> resultMap = null;
        try {
            logger.info("------------->开始调用grade-student addStudentScoreList，param：tableName:{},operator:{},studentScoreDTOList:{}", tableName, operator, studentScoreDTOList);
            resultMap = studentScoreDubboService.addStudentScoreList(tableName, operator, studentScoreDTOList);
            logger.info("------------->调用grade-student addStudentScoreList 结束 result：{}", resultMap);

        } catch (StudentException e) {
            e.printStackTrace();
        }
        logger.info("------------->导入学生信息表完毕，耗时：{}", System.currentTimeMillis() - begain);

        //开始处理数据校验未通过的学生
        List<StudentScoreDTO> failStudentScoreDTO = (List<StudentScoreDTO>) resultMap.get("failStudentScore");
        if (failStudentScoreDTO != null && failStudentScoreDTO.size() > 0) {
            //开始导出数据为csv文件
            if (failStudentScoreDTO != null && failStudentScoreDTO.size() > 0) {
                List<String> title = new ArrayList<>();
                title.addAll(Arrays.asList("学号,姓名,申请部门,申请原因,申请分数,审批分数,页码,失败原因")); //csv 标题
                List<List<String>> content = new ArrayList<>(); //csv内容
                failStudentScoreDTO.stream().forEach(failStudentScore -> {
                    List<String> record = new ArrayList<>();
                    record.add(failStudentScore.getStudentNumber().toString());
                    record.add(failStudentScore.getName());
                    record.add(failStudentScore.getRemark());
                    record.add(failStudentScore.getReason());
                    record.add(failStudentScore.getApplyScore().toString());
                    record.add(failStudentScore.getFinallyScore().toString());
                    record.add(failStudentScore.getPage());
                    record.add(failStudentScore.getFailReason());
                    content.add(record);
                });
                String uploadPath = "grade/studentScoreInfo/errorData/"; //定义文件名
                String uploadName = "学生操行信息导入失败数据" + DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:mm:ss") + "-" + operator;
                exportService.export(uploadName, uploadPath, title, content, operator, 1);
            }
        }
        //记录一下总共多少记录，多少导入成功，多少导入失败
        importFailCount = failStudentScoreDTO.size();
        importSuccessCount = totalCount - importFailCount;
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("totalCount", totalCount + "");
        map.put("importSuccessCount", importSuccessCount + "");
        map.put("importFailCount", importFailCount + "");
        return map;
    }

    /**
     * 2007版导入班级信息
     *
     * @param fileName
     * @return
     */
    private Map<String, Object> importClassByExcel2007(String fileName) {
        return null;
    }

    /**
     * 2007版导入学生信息
     *
     * @param fileName
     * @return
     */
    private Map<String, Object> importStudentByExcel2007(
            String fileName, String userName) throws AdminException {
        List<StudentDTO> students = new ArrayList<StudentDTO>();
        boolean startCount = false;
        int totalCount = 0;
        int importSuccessCount = 0;
        int importFailCount = 0;

        FileInputStream input = null;
        XSSFWorkbook wb = null;
        StudentDTO s = null;
        try {
            input = new FileInputStream(new File(fileName));
            wb = new XSSFWorkbook(new BufferedInputStream(input));
        } catch (IOException e) {
            e.printStackTrace();
        }
        XSSFSheet sheet = wb.getSheetAt(0);
        long begain = System.currentTimeMillis();
        logger.info("开始读取excel文件--------->,文件名：{}", fileName);
        for (int rows = 0; rows <= sheet.getLastRowNum(); rows++) {
            XSSFRow row = sheet.getRow(rows);
            String content = null;
            s = new StudentDTO();
            for (int columns = 0; columns < row.getLastCellNum(); columns++) {
                XSSFCell cell = row.getCell(columns);
                if (cell != null) {
                    if ("".equals(cell.toString())) {
                        content = "";
                    }
                    switch (cell.getCellTypeEnum()) {
                        case STRING:
                            content = cell.getStringCellValue();
                            break;
                        case NUMERIC:
                            if (columns == 0) {
                                DecimalFormat df = new DecimalFormat("0");
                                content = df.format(cell.getNumericCellValue());
                                break;
                            }

                            if (columns == 2) {
                                DecimalFormat df = new DecimalFormat("0");
                                content = df.format(cell.getNumericCellValue());
                                break;
                            }

                            break;
                        case FORMULA: // 空值
                            break;
                        default:
                            break;
                    }
                    if (content != null && content != "") {
                        if (columns == 0 && isNumber(content)) {
                            startCount = true;
                            totalCount++;
                        }
                        if (columns == 0 && !isNumber(content) && startCount) {
                            startCount = false;
                        }
                        if (columns == row.getLastCellNum() - 1 && startCount) {
                            students.add(s);
                        }
                        if (startCount) {
                            switch (columns) {
                                case 0:
                                    s.setStudentNumber(Long.parseLong(content));
                                    break;
                                case 1:
                                    s.setName(content);
                                    break;
                                case 2:
                                    s.setClassNumber(Long.parseLong(content));
                                    break;
                                case 3:
                                    s.setDuty(content);
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
        }
        logger.info("读取excel文件结束--------->,耗时：{}", System.currentTimeMillis() - begain);
        logger.info("开始批量存入数据库......");
        long begainToMysql = System.currentTimeMillis();
        Map<String, Object> resultMap = null;
        try {
            logger.info("调用grade-student addStudentList，param:{}", students);
            resultMap = studentDubboService.addStudentList(students);
            logger.info("调用grade-student addStudentList，result:{}", resultMap);
        } catch (StudentException e) {
            logger.error("error", e);
            throw AdminException.internalServerError();
        }

        logger.info("批量存入数据库完毕，耗时：{}", System.currentTimeMillis() - begainToMysql);
        importFailCount = (int) resultMap.get("failResult");
        importSuccessCount = totalCount - importFailCount;
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("totalCount", totalCount + "");
        map.put("importSuccessCount", importSuccessCount + "");
        map.put("importFailCount", importFailCount + "");
        map.put("importFailReason", resultMap.get("failReason"));
        if (resultMap.get("failReason") != null) {
            List<StudentDTO> failList = (List<StudentDTO>) resultMap.get("failReason");
            //开始导出数据为csv文件
            if (failList != null && failList.size() > 0) {
                List<String> title = new ArrayList<>();
                title.addAll(Arrays.asList("学号,姓名,职位,班级编号,导入失败原因")); //csv 标题
                List<List<String>> content = new ArrayList<>(); //csv内容
                failList.stream().forEach(failStudent -> {
                    List<String> record = new ArrayList<>();
                    record.add(failStudent.getStudentNumber().toString());
                    record.add(failStudent.getName());
                    record.add(failStudent.getDuty());
                    record.add(failStudent.getClassNumber().toString());
                    record.add(failStudent.getFailReason());
                    content.add(record);
                });
                String uploadPath = "grade/studentInfo/errorData/"; //定义文件名
                String uploadName = "学生信息导入失败数据" + DateUtil.DateToString(new Date(), "yyyy-MM-dd HH:ss:mm") + "-" + userName;
                exportService.export(uploadName, uploadPath, title, content, userName, 1);
            }
        }
        return map;
    }


    public boolean isNumber(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }


    public StringBuffer batchStudentInfoToCsv(List<StudentDTO> list) {
        StringBuffer content = new StringBuffer("");
        for (StudentDTO student : list) {
            content.append(student.getStudentNumber()).append(",");
            content.append(student.getName()).append(",");
            content.append(student.getDuty()).append(",");
            content.append(student.getClassNumber()).append(",");
            content.append(student.getFailReason()).append(",");
            content.append("\n");
        }
        return content;
    }

    public StringBuffer exportStudentInfoToCsv(List<StudentDTO> list, String className) {
        StringBuffer content = new StringBuffer("");
        for (StudentDTO student : list) {
            content.append(student.getStudentNumber()).append(",");
            content.append(student.getName()).append(",");
            content.append(className).append(",");
            content.append(student.getDuty()).append(",");
            content.append(student.getScore()).append(",");
            content.append("\n");
        }
        return content;
    }

    public StringBuffer exportClassInfoToCsv(List<ClassDTO> list) {
        StringBuffer content = new StringBuffer("");
        for (ClassDTO classDTO : list) {
            content.append(classDTO.getClassNumber()).append(",");
            content.append(classDTO.getClassName()).append(",");
            content.append(classDTO.getMonitor()).append(",");
            content.append(classDTO.getScore()).append(",");
            content.append("\n");
        }
        return content;
    }

    public StringBuffer batchStudentScoreInfoToCsv(List<StudentScoreDTO> list) {
        StringBuffer content = new StringBuffer("");
        for (StudentScoreDTO studentScoreDTO : list) {
            content.append(studentScoreDTO.getStudentNumber()).append(",");
            content.append(studentScoreDTO.getName()).append(",");
            content.append(studentScoreDTO.getRemark()).append(",");
            content.append(studentScoreDTO.getReason()).append(",");
            content.append(studentScoreDTO.getApplyScore()).append(",");
            content.append(studentScoreDTO.getFinallyScore()).append(",");
            content.append(studentScoreDTO.getPage()).append(",");
            content.append(studentScoreDTO.getReason()).append(",");
            content.append("\n");
        }
        return content;
    }
}
